package cn.xiuxius.embedded.runconfig.ui;

import cn.xiuxius.embedded.runconfig.EasySTCRunConfigurationOptions;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.components.*;
import com.intellij.ui.components.fields.IntegerField;
import com.intellij.util.ui.FormBuilder;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.util.*;
import java.util.List;
import java.util.function.Consumer;

public class AdvFlashTaskPanel implements TaskSettingsPanel {
    // Fixed components
    private final ComboBox<SerialPortOption> portComboBox = new ComboBox<>();
    private final JButton refreshPortsButton = new JButton("刷新");
    private final ComboBox<ProtocolOption> protocolComboBox = new ComboBox<>();
    private final ComboBox<BooleanOption> eepromEraseComboBox = new ComboBox<>();
    private final JBCheckBox programEepromSplitCheckBox = new JBCheckBox("启用程序/EEPROM分区");
    private final IntegerField programEepromSplitField = new IntegerField("用户EEPROM大小", 512, 65024);

    // Dynamic options components
    private final ComboBox<AdvancedOption> availableOptionsComboBox = new ComboBox<>();
    private final JButton addOptionButton = new JButton("添加选项");
    private JBScrollPane optionsScrollPane;
    private final JPanel optionsContainerPanel = new JPanel();
    private final JPanel optionsListPanel = new JPanel();

    // Main panel
    private final JPanel panel;

    // Data structures for managing options
    private final List<AdvancedOption> availableOptions = new ArrayList<>();
    private final List<ActiveOption> activeOptions = new ArrayList<>();

    public interface PortRefreshCallback {
        List<SerialPortOption> getAvailablePorts();
    }

    public AdvFlashTaskPanel() {
        // Initialize the UI
        initAvailableOptions();
        initFixedComponents();
        initDynamicOptionsComponents();

        // Build the main panel
        panel = FormBuilder.createFormBuilder()
                .addLabeledComponent("串口:", createPortSelectionPanel())
                .addLabeledComponent("协议:", protocolComboBox)
                .addLabeledComponent("EEPROM擦除:", eepromEraseComboBox)
                .addLabeledComponent("", createEepromSplitPanel())
                .addSeparator()
                .addLabeledComponent("高级选项:", createDynamicOptionsPanel())
                .getPanel();
    }

    private void initAvailableOptions() {
        // Boolean type options
        addAvailableOption(new BooleanOption("watchdogPorEnabled", "上电复位看门狗", "--watchdog-por"));
        addAvailableOption(new BooleanOption("bslPindetectEnabled", "BSL引脚检测", "--bsl-pindetect"));
        addAvailableOption(new BooleanOption("resetPinEnabled", "复位引脚模式", "--reset-pin"));
        addAvailableOption(new BooleanOption("aleEnabled", "ALE引脚", "--ale"));

        // Enum type options
        addAvailableOption(new EnumOption("porResetDelay", "上电复位延迟", "--por-reset-delay",
                Arrays.asList(new EnumValue("SHORT", "短延迟"),
                        new EnumValue("LONG", "长延迟"),
                        new EnumValue("DEFAULT", "默认"))));

        addAvailableOption(new EnumOption("cpuCoreVoltage", "CPU核心电压", "--cpu-core-voltage",
                Arrays.asList(new EnumValue("LOW", "低"),
                        new EnumValue("MEDIUM", "中"),
                        new EnumValue("HIGH", "高"),
                        new EnumValue("DEFAULT", "默认"))));

        addAvailableOption(new EnumOption("clockSource", "时钟源", "--clock-source",
                Arrays.asList(new EnumValue("INTERNAL", "内部"),
                        new EnumValue("EXTERNAL", "外部"),
                        new EnumValue("DEFAULT", "默认"))));

        addAvailableOption(new EnumOption("rstoutPorState", "RSTOUT上电状态", "--rstout-por",
                Arrays.asList(new EnumValue("LOW", "低电平"),
                        new EnumValue("HIGH", "高电平"),
                        new EnumValue("DEFAULT", "默认"))));

        addAvailableOption(new EnumOption("uart2PinMode", "UART2引脚模式", "--uart2-pin-mode",
                Arrays.asList(new EnumValue("DEFAULT", "默认"),
                        new EnumValue("PASSTHROUGH", "直通"),
                        new EnumValue("REMAP", "重映射"))));

        // Numeric type options
        addAvailableOption(new NumericOption("programEepromSplit", "程序/EEPROM分区", "--program-eeprom-split", 512, 65024, 512));
        addAvailableOption(new NumericOption("watchdogPrescale", "看门狗预分频", "--watchdog-prescale", 2, 256, 2));
    }

    private void addAvailableOption(AdvancedOption option) {
        availableOptions.add(option);
        availableOptionsComboBox.addItem(option);
    }

    private void initFixedComponents() {
        // Port selection
        refreshPortList();

        // Protocol selection
        protocolComboBox.setModel(new DefaultComboBoxModel<>(new ProtocolOption[]{
                new ProtocolOption("auto", "自动"),
                new ProtocolOption("stc89", "STC89"),
                new ProtocolOption("stc12a", "STC12A"),
                new ProtocolOption("stc12b", "STC12B"),
                new ProtocolOption("stc12", "STC12"),
                new ProtocolOption("stc15a", "STC15A"),
                new ProtocolOption("stc15", "STC15"),
                new ProtocolOption("stc8", "STC8"),
                new ProtocolOption("stc8d", "STC8D"),
                new ProtocolOption("stc8g", "STC8G"),
                new ProtocolOption("usb15", "USB15")
        }));
        protocolComboBox.setSelectedItem(new ProtocolOption("auto", "自动"));

        // EEPROM settings
        eepromEraseComboBox.setModel(new DefaultComboBoxModel<>(new BooleanOption[]{
                new BooleanOption("default", "默认", "--eeprom-erase"),
                new BooleanOption("true", "启用", "--eeprom-erase"),
                new BooleanOption("false", "禁用", "--eeprom-erase")
        }));
        eepromEraseComboBox.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, int index,
                                                          boolean isSelected, boolean cellHasFocus) {
                if (value instanceof BooleanOption) {
                    value = ((BooleanOption) value).getDisplayName();
                }
                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            }
        });
        eepromEraseComboBox.setSelectedItem(new BooleanOption("default", "默认", "--eeprom-erase"));

        // Program/EEPROM split
        programEepromSplitField.setEnabled(false);
        programEepromSplitField.setValue(512);
        programEepromSplitCheckBox.addItemListener(e -> {
            programEepromSplitField.setEnabled(e.getStateChange() == ItemEvent.SELECTED);
        });
    }

    private void initDynamicOptionsComponents() {
        // Available options combo box
        availableOptionsComboBox.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                if (value instanceof AdvancedOption) {
                    value = ((AdvancedOption) value).getDisplayName();
                }
                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            }
        });

        // Add option button
        addOptionButton.addActionListener(this::handleAddOption);

        // Options list panel setup
        optionsListPanel.setLayout(new BoxLayout(optionsListPanel, BoxLayout.Y_AXIS));
        optionsContainerPanel.setLayout(new BorderLayout());
        optionsContainerPanel.add(optionsListPanel, BorderLayout.NORTH);
        optionsScrollPane = new JBScrollPane(optionsContainerPanel);
        optionsScrollPane.setPreferredSize(JBUI.size(400, 200));
    }

    private JPanel createPortSelectionPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(portComboBox, BorderLayout.CENTER);
        panel.add(refreshPortsButton, BorderLayout.EAST);
        refreshPortsButton.addActionListener(e -> refreshPortList());
        return panel;
    }

    private JPanel createEepromSplitPanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(programEepromSplitCheckBox, BorderLayout.WEST);
        panel.add(programEepromSplitField, BorderLayout.CENTER);
        return panel;
    }

    private JPanel createDynamicOptionsPanel() {
        JPanel panel = new JPanel(new BorderLayout());

        JPanel topPanel = new JPanel(new BorderLayout());
        topPanel.add(availableOptionsComboBox, BorderLayout.CENTER);
        topPanel.add(addOptionButton, BorderLayout.EAST);

        panel.add(topPanel, BorderLayout.NORTH);
        panel.add(optionsScrollPane, BorderLayout.CENTER);

        return panel;
    }

    private void refreshPortList() {
        portComboBox.setSelectedItem(new SerialPortOption("AUTO", "自动"));
    }

    private void updateAvailableOptionsComboBox() {
        AdvancedOption current = availableOptionsComboBox.getItem();
        availableOptionsComboBox.removeAllItems();

        availableOptions.stream()
                .filter(option -> activeOptions.stream().noneMatch(active -> active.getOption().equals(option)))
                .forEach(availableOptionsComboBox::addItem);

        if (current != null && availableOptions.contains(current) &&
                activeOptions.stream().noneMatch(active -> active.getOption().equals(current))) {
            availableOptionsComboBox.setSelectedItem(current);
        }
    }

    private void handleAddOption(ActionEvent e) {
        AdvancedOption selectedOption = availableOptionsComboBox.getItem();
        if (selectedOption == null) return;

        ActiveOption activeOption = new ActiveOption(selectedOption);
        if (activeOption.validate()) {
            activeOptions.add(activeOption);
            optionsListPanel.add(activeOption.getPanel());
            optionsListPanel.revalidate();
            optionsListPanel.repaint();
            updateAvailableOptionsComboBox();
        }
    }

    private void removeActiveOption(ActiveOption option) {
        activeOptions.remove(option);
        optionsListPanel.remove(option.getPanel());
        optionsListPanel.revalidate();
        optionsListPanel.repaint();
        updateAvailableOptionsComboBox();
    }

    @Override
    public @NotNull JPanel getComponent() {
        return panel;
    }

    @Override
    public void resetFrom(@NotNull EasySTCRunConfigurationOptions options) {
        // TODO: Implement loading from options
    }

    @Override
    public void applyTo(@NotNull EasySTCRunConfigurationOptions options) {
        // TODO: Implement saving to options
    }

    // ==================== Data Model Classes ====================

    public static class SerialPortOption {
        private final String name;
        private final String displayName;

        public SerialPortOption(String name, String displayName) {
            this.name = name;
            this.displayName = displayName;
        }

        public String getName() {
            return name;
        }

        public String getDisplayName() {
            return displayName;
        }

        @Override
        public String toString() {
            return displayName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            SerialPortOption that = (SerialPortOption) o;
            return name.equals(that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }

    public static class ProtocolOption {
        private final String name;
        private final String displayName;

        public ProtocolOption(String name, String displayName) {
            this.name = name;
            this.displayName = displayName;
        }

        public String getName() {
            return name;
        }

        public String getDisplayName() {
            return displayName;
        }

        @Override
        public String toString() {
            return displayName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ProtocolOption that = (ProtocolOption) o;
            return name.equals(that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }

    public static class EnumValue {
        private final String name;
        private final String displayName;

        public EnumValue(String name, String displayName) {
            this.name = name;
            this.displayName = displayName;
        }

        public String getName() {
            return name;
        }

        public String getDisplayName() {
            return displayName;
        }

        @Override
        public String toString() {
            return displayName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            EnumValue that = (EnumValue) o;
            return name.equals(that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }

    public abstract static class AdvancedOption {
        protected final String name;
        protected final String displayName;
        protected final String commandOption;

        public AdvancedOption(String name, String displayName, String commandOption) {
            this.name = name;
            this.displayName = displayName;
            this.commandOption = commandOption;
        }

        public String getName() {
            return name;
        }

        public String getDisplayName() {
            return displayName;
        }

        public String getCommandOption() {
            return commandOption;
        }

        public abstract boolean validate(String value);

        public abstract String getDefaultValue();

        public abstract JComponent createEditorComponent(Consumer<String> valueChangeListener);

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            AdvancedOption that = (AdvancedOption) o;
            return name.equals(that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    }

    public static class BooleanOption extends AdvancedOption {
        public BooleanOption(String name, String displayName, String commandOption) {
            super(name, displayName, commandOption);
        }

        @Override
        public boolean validate(String value) {
            return value != null;
        }

        @Override
        public String getDefaultValue() {
            return "default";
        }

        @Override
        public JComponent createEditorComponent(Consumer<String> valueChangeListener) {
            ComboBox<EnumValue> comboBox = new ComboBox<>(new EnumValue[]{
                    new EnumValue("default", "默认"),
                    new EnumValue("true", "启用"),
                    new EnumValue("false", "禁用")
            });
            comboBox.setSelectedIndex(0);
            comboBox.addItemListener(e -> {
                EnumValue selected = (EnumValue) comboBox.getSelectedItem();
                if (selected != null) {
                    valueChangeListener.accept(selected.getName());
                }
            });
            return comboBox;
        }
    }

    public static class EnumOption extends AdvancedOption {
        private final List<EnumValue> values;

        public EnumOption(String name, String displayName, String commandOption, List<EnumValue> values) {
            super(name, displayName, commandOption);
            this.values = new ArrayList<>(values);
        }

        @Override
        public boolean validate(String value) {
            return values.stream().anyMatch(v -> v.getName().equals(value));
        }

        @Override
        public String getDefaultValue() {
            return values.stream()
                    .filter(v -> "DEFAULT".equals(v.getName()))
                    .findFirst()
                    .orElse(values.get(0))
                    .getName();
        }

        @Override
        public JComponent createEditorComponent(Consumer<String> valueChangeListener) {
            ComboBox<EnumValue> comboBox = new ComboBox<>(values.toArray(new EnumValue[0]));
            comboBox.setSelectedItem(values.stream()
                    .filter(v -> "DEFAULT".equals(v.getName()))
                    .findFirst()
                    .orElse(values.get(0)));
            comboBox.addItemListener(e -> {
                EnumValue selected = (EnumValue) comboBox.getSelectedItem();
                if (selected != null) {
                    valueChangeListener.accept(selected.getName());
                }
            });
            return comboBox;
        }
    }

    public static class NumericOption extends AdvancedOption {
        private final int minValue;
        private final int maxValue;
        private final int step;

        public NumericOption(String name, String displayName, String commandOption, int minValue, int maxValue, int step) {
            super(name, displayName, commandOption);
            this.minValue = minValue;
            this.maxValue = maxValue;
            this.step = step;
        }

        @Override
        public boolean validate(String value) {
            try {
                int num = Integer.parseInt(value);
                return num >= minValue && num <= maxValue && num % step == 0;
            } catch (NumberFormatException e) {
                return false;
            }
        }

        @Override
        public String getDefaultValue() {
            return String.valueOf(minValue);
        }

        @Override
        public JComponent createEditorComponent(Consumer<String> valueChangeListener) {
            IntegerField field = new IntegerField();
            field.setColumns(10);
            field.setMinValue(minValue);
            field.setMaxValue(maxValue);
            field.getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent e) {
                    notifyChange();
                }

                @Override
                public void removeUpdate(DocumentEvent e) {
                    notifyChange();
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                    notifyChange();
                }

                private void notifyChange() {
                    valueChangeListener.accept(field.getText());
                }
            });
            return field;
        }
    }

    private class ActiveOption {
        private final AdvancedOption option;
        private String currentValue;
        private final JPanel panel;

        public ActiveOption(AdvancedOption option) {
            this.option  = option;
            this.currentValue  = option.getDefaultValue();
            this.panel  = createOptionPanel();
        }

        // 添加验证方法
        public boolean validate() {
            return option.validate(currentValue);
        }

        private JPanel createOptionPanel() {
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBorder(JBUI.Borders.empty(5,  0));

            // 主内容面板
            JPanel contentPanel = new JPanel(new BorderLayout());

            // 选项标签
            JLabel label = new JLabel(option.getDisplayName());
            label.setBorder(JBUI.Borders.emptyRight(5));
            contentPanel.add(label,  BorderLayout.WEST);

            // 值编辑器组件
            JComponent editor = option.createEditorComponent(value  -> {
                if (option.validate(value))  {
                    currentValue = value;
                }
            });
            contentPanel.add(editor,  BorderLayout.CENTER);

            // 使用标准JB按钮
            JButton removeButton = new JButton("删除");
            removeButton.setMargin(JBUI.insets(2,  8));
            removeButton.addActionListener(e  -> removeActiveOption(this));

            // 按钮容器
            JPanel buttonPanel = new JPanel(new BorderLayout());
            buttonPanel.setBorder(JBUI.Borders.emptyLeft(10));
            buttonPanel.add(removeButton,  BorderLayout.EAST);

            contentPanel.add(buttonPanel,  BorderLayout.EAST);
            panel.add(contentPanel,  BorderLayout.CENTER);

            return panel;
        }

        // Getter方法
        public AdvancedOption getOption() {
            return option;
        }

        public String getValue() {
            return currentValue;
        }

        public JPanel getPanel() {
            return panel;
        }
    }
}